One can only hope that developers who implement HTTP calls in their Flutter apps are aware of the `RetryClient
` class. Although http
examples provided by streamlined tutorials across the web are helpful, they may not always provide a complete picture of the `http` package’s capabilities. And because calls to common API endpoints are typically developed under happy path conditions, it can be easy to overlook the need for something like the RetryClient
class.
[http: RetryClient] By default, this retries any request whose response has status code 503 Temporary Failure up to three retries. It waits 500ms before the first retry, and increases the delay by 1.5x each time. All of this can be customized using the
Google: pub.dev | http packageRetryClient()
constructor.
I was attempting to fix an uncaught exception error when loading an app on an emulator when I discovered the RetryClient
class. And although it didn’t help fix that particular exception, it really felt this class should be a part of any HTTP call. Like, http
and the RetryClient
wrapper should be part and parcel to every HTTP call. Like selling hardware firewalls with computers. Like, a house with a roof. Or, you know, like, peanut butter and talking horses.
In any case, I couldn’t find many expanded examples for the RetryClient
class in my search, so I took a little time to develop it out manually. The following is the result.
I hope it helps someone, and I’m always open to suggestions for making things better.
import 'dart:developer';
///
/// *** The CONFIGS ***
///
/// These HTTP response status codes determine if an HTTP call is retried below.
/// Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
final httpRetryResponseStatusCodes = <int>[
400, // | Bad Request
401, // | Unauthorized
403, // | Forbidden
404, // | Not Found
408, // | Request Timeout
409, // | Conflict
429, // | Too Many Requests
500, // | Internal Server Error
502, // | Bad Gateway
503, // | Service Unavailable (Temporary Failure)
504, // | Gateway Timeout
];
const apiUrl = 'https://yourdomain.com/api/endpoint.php';
final apiUri = Uri.parse(apiUrl);
const apiErr = 'Retry error: Please check your connection and try again.';
const whichForm = 'login';
final returnObj = <String, List<dynamic>>{
'httpStatus': [],
'status': [],
'message': [],
'whichForm': [whichForm],
};
final (userId, token) = await _injectedNetworkServiceApi.getAuthInfo;
final urlData = {
'userId': userId,
'userToken': token,
'whichForm': whichForm,
};
late final Response response;
///
/// *** The RETRY ***
///
/// RetryClient Sources:
/// https://pub.dev/packages/http#retrying-requests
/// https://pub.dev/documentation/http/latest/retry/RetryClient-class.html
///
final client = RetryClient(
http.Client(),
// retries: 7, // Default: 3
whenError: (error, stackTrace) => true,
when: (response) => httpRetryResponseStatusCodes.contains(response.statusCode),
onRetry: (request, response, retryCount) {
log('[RetryClient] [onRetry] [$retryCount] $request');
},
);
try {
response = await client.post(
apiUri,
body: json.encode(urlData),
);
} catch (err) {
returnObj['httpStatus']!.add('500');
returnObj['status']!.add('error');
returnObj['message']!.add(apiErr);
return returnObj;
//
} finally {
client.close();
}
final responseData = json.decode(response.body) as Map<String, dynamic>;
Cheers!
– Keith | https://keithdc.com